#ifndef AASTAR_H
#define AASTAR_H

#include "config.h"
#include "astar.h"
#include <cmath>

struct LODESTAR_API MapTile
{
    MapTile(int _x, int _y) : x(_x), y(_y) {}
    int x;
    int y;

    bool operator == (const MapTile& tile) const
    {
        return x == tile.x && y == tile.y;
    }
};

class LODESTAR_API MapZone
{
public:
    class LODESTAR_API Node
    {
    public:
        Node() :_tile(0, 0), _map(nullptr) {}
        Node(MapZone* map, int x, int y) : _map(map), _tile(x, y) {}

        float GoalDistanceEstimate(const Node& goal) const
        {
            return abs(_tile.x - goal._tile.x) + abs(_tile.y - goal._tile.y);
        }

        bool IsGoal(const Node& nodeGoal) const
        {
            return IsSameState( nodeGoal );
        }

        bool IsSameState(const Node& other) const
        {
            return _tile == other._tile;
        }

        float GetCost(const Node& other) const
        {
            return 1.0f;
        }

        bool GetSuccessors(AStarSearch<Node>* search, const Node* parentNode) const
        {
            static const int tile_offsets[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};

            for (unsigned int i = 0; i < 4; ++i)
            {
                MapTile tile(_tile.x + tile_offsets[i][0], _tile.y + tile_offsets[i][1]);
                if (_map->isPointInside(tile.x, tile.y) && _map->isPassable(tile.x, tile.y) && !(parentNode != nullptr && parentNode->_tile == tile))
                {
                    Node newNode(_map, tile.x, tile.y);
                    search->AddSuccessor(newNode);
                }
            }
            return true;
        }

        const MapTile& getTile() const {return _tile;}
    protected:
        MapTile _tile;
        MapZone* _map;
    };

    MapZone();
    ~MapZone();

    bool init( size_t width, size_t height );

    bool isPassable( size_t x, size_t y) const;


    void setPassable( size_t x, size_t y, bool passable) const;

    bool isPointInside( int x, int y ) const;

    bool findPath(const MapTile& start, const MapTile& end, vector<MapTile>* path);
protected:
    size_t getIndexForPoint( size_t y, size_t x ) const;
    // actual size
    size_t _width;
    size_t _height;

    // power of 2. 2 ^ _logWidth >= _width
    size_t _logWidth;

    bool* _map;
};
#endif